using System;

namespace UnitTests.Foundation
{
    /// <summary>
    /// Builder for test contexts.
    /// Use this builder to create instances of you test context with applied test scenarios.
    /// </summary>
    /// <typeparam name="TContext">Type of test context to build.</typeparam>
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design",
        "CA1001:TypesThatOwnDisposableFieldsShouldBeDisposable", Justification = "This is a factory.")]
    public class TestContextBuilder<TContext>
        where TContext : TestContext, new()
    {
        private readonly TContext _context;

        /// <summary>
        /// Initializes a new instance of the <see cref="TestContextBuilder&lt;T&gt;"/> class.
        /// </summary>
        public TestContextBuilder()
        {
            _context = new TContext();
        }

        /// <summary>
        /// Adds a customization to the test context being built.
        /// </summary>
        /// <param name="contextAction">The customization action to perform against the test context.</param>
        /// <returns>The test context builder.</returns>
        public TestContextBuilder<TContext> WithScenario(Action<TContext> contextAction)
        {
            contextAction(_context);
            return this;
        }

        /// <summary>
        /// Adds a customization to the test context being built.
        /// </summary>
        /// <typeparam name="T2">The type of the parameter 1 to the customization.</typeparam>
        /// <param name="contextAction">The customization action to perform against the test context.</param>
        /// <param name="param1">The parameter 1.</param>
        /// <returns>The test context builder.</returns>
        public TestContextBuilder<TContext> WithScenario<T2>(Action<TContext, T2> contextAction, T2 param1)
        {
            contextAction(_context, param1);
            return this;
        }

        /// <summary>
        /// Adds a customization to the test context being built.
        /// </summary>
        /// <typeparam name="T2">The type of the parameter 1 to the customization.</typeparam>
        /// <typeparam name="T3">The type of the parameter 2 to the customization.</typeparam>
        /// <param name="contextAction">The customization action to perform against the test context.</param>
        /// <param name="param1">The parameter 1.</param>
        /// <param name="param2">The parameter 2.</param>
        /// <returns>The test context builder.</returns>
        public TestContextBuilder<TContext> WithScenario<T2, T3>(Action<TContext, T2, T3> contextAction, T2 param1, T3 param2)
        {
            contextAction(_context, param1, param2);
            return this;
        }

        /// <summary>
        /// Builds the test context.
        /// </summary>
        /// <returns>The test context.</returns>
        public TContext Create()
        {
            _context.Initialize();
            return _context;
        }
    }
}
